package com.ljf.eslab.lab.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ljf.common.utils.*;
import com.ljf.eslab.lab.dto.IdsAndCourseIdDTO;
import com.ljf.eslab.lab.dto.ReserInfoDTO;
import com.ljf.eslab.lab.entity.CourseEntity;
import com.ljf.eslab.lab.entity.LabEntity;
import com.ljf.eslab.lab.service.*;
import com.ljf.eslab.lab.vo.ReserDetailVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import com.ljf.eslab.lab.entity.ReservationEntity;

import javax.servlet.http.HttpServletRequest;


/**
 * @author ljf
 * @email ljf@gmail.com
 * @date 2021-05-28 09:12:59
 */
@Slf4j
@RestController
@RequestMapping("lab/reservation")
public class ReservationController {
    @Autowired
    private ReservationService reservationService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private LabService labService;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private TeacherService teacherService;

    @Autowired
    private ObjectMapper objectMapper;
    /**
     * 列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params) {
        PageUtils page = reservationService.queryPage(params);

        return R.ok().put("page", page);
    }

    /**
     * 信息
     */
    @Cacheable(value = "reservation",key = "#id")
    @RequestMapping("/info/{id}")
    public R info(@PathVariable("id") Integer id) {
        ReservationEntity reservation = reservationService.getById(id);

        return R.ok().put("reservation", reservation);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody ReservationEntity reservation) {
        reservationService.save(reservation);

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@RequestBody ReservationEntity reservation) {
        reservationService.updateById(reservation);

        return R.ok();
    }

    /**
     * 退选，根据传入的ids完成退选
     */
    @RequestMapping("/deleteIds")
    public R updateStatusOne(HttpServletRequest request, @RequestBody IdsAndCourseIdDTO dto) {
        List<Integer> ids = dto.getIds();
        //找到userid对应teacherid
        Integer tid = (Integer) request.getAttribute("tid");
        if (tid == null)
            return R.error("不是老师，无权限删除");
        //拿到老师id对应的所有课程id
        HashSet<Integer> cidsOfTeacher = courseService.getByTID(tid);
        //拿到预约记录ids对应的所有课程id
        List<Integer> cidsInRsvNotOfTeacher = reservationService.listByIds(ids).stream()
                .map(ReservationEntity::getCourseId)
                .filter(cidInRsv -> {
                    return !cidsOfTeacher.contains(cidInRsv);
                })
                .collect(Collectors.toList());
        //ids存在一个课程id不在老师的课程id则拒绝删除，返回删除失败
        if (cidsInRsvNotOfTeacher.size() > 0) {
            String msg = "退选失败,有" + cidsInRsvNotOfTeacher.size() + "个预约记录的课程无权限退选";
            return R.error(msg);
        }
        //否则更新ids对course_id 为0
        reservationService.updateCidByIds(ids, 0);

        return R.ok();
    }

    /**
     * 选课,根据预约记录的ids完成选课
     */
    @PostMapping("/updateIds")
    public R updateStatusZero(HttpServletRequest request,@RequestBody IdsAndCourseIdDTO idsAndCourseIdDTO) {
        List<Integer> ids = idsAndCourseIdDTO.getIds();
        Integer courseId = idsAndCourseIdDTO.getCourseId();
        //找到userid对应teacherid
        Integer tid = (Integer) request.getAttribute("tid");
        if (tid == null)
            return R.error("不是老师，无权限选课");
        //拿到预约记录ids对应的所有课程id为1，即不可选的预约记录， ids
        List<ReservationEntity> wrongRsvs = reservationService.listByIds(ids)
                .stream()
                .filter(c -> c.getCourseId() != 0)
                .collect(Collectors.toList());
        //如果存在不可预约，则返回错误
        if (wrongRsvs.size() > 0) {
            StringBuilder msg = new StringBuilder();
            msg.append("存在预约冲突");
            for (ReservationEntity wrongRsv : wrongRsvs) {
                msg.append("时间：").append("第").append(wrongRsv.getWeek()).append("周 ,")
                        .append("周").append(wrongRsv.getDayOfWeek()).append(" ,")
                        .append("第").append(wrongRsv.getTimeOfDay()).append("节课 ,")
                        .append("已经被选\n");
            }
            return R.error(msg.toString());
        }
        //否则更新ids对应课程的课程号0为真正课程id,即把状态从可选变为不可选
        reservationService.updateCidByIds(ids, courseId);

        return R.ok();
    }


    /**
     * 输入课程id，时间范围
     * 返回合适的预约记录集合的分页信息
     *
     * @param params
     * @return
     */
    @GetMapping("/listByTimeAndCourse")
    public R listByTimeAndCourse(@RequestParam Map<String, Object> params) {
        //如果不包含课程id信息，就按照时间参数查询能预约的预约记录
        if (!params.containsKey("courseId")) {
            return listByTime(params);
        }
        //查询传入参数中课程id对应符合课程，
        // 如果不存在该课程，则也按照仅时间查询处理
        Integer courseId = ParamsUtil.getInteger(params, "courseId");
        CourseEntity course = courseService.getById(courseId);
        if (course == null) {
            return listByTime(params);
        }
        Integer weekStart = ParamsUtil.getInteger(params, "weekStart");
        Integer weekEnd = ParamsUtil.getInteger(params, "weekEnd");
        List<Integer> weeks = ParamsUtil.getBetweenIntegers(weekStart, weekEnd, 1);
        List<Integer> days = ParamsUtil.getIntegerList(params, "dayOfWeek");
        List<Integer> times = ParamsUtil.getIntegerList(params, "timeOfDay");
        //拿到容量大于课程学时数的所有实验室
        List<LabEntity> labs = labService.list(new QueryWrapper<LabEntity>().ge("capicity", course.getStuCount()));
        List<Integer> labIds = labs.stream().map(LabEntity::getId).collect(Collectors.toList());
        //在容量合适的实验室中，
        // 挑选在时间范围内、全都有空闲的实验室的
        // 规定时间内的预约记录
        PageUtils page = reservationService.pageByTimeAndIds(new Query<ReserDetailVo>().getPage(params),weeks, days, times, labIds);

        if (page.getList().size() == 0) {
            return R.ok().put("page", new PageUtils(List.of(), params));
        }
        return R.ok().put("page", page);
    }
    /**
     * 输入课程id，时间范围
     * 返回合适的实验室名称以及id等信息
     *
     * @param params
     * @return
     */
    @GetMapping("/listLabNameByTimeAndCourse")
    public R listLabNameByTimeAndCourse(@RequestParam Map<String, Object> params) {
        //如果不包含课程id信息，就按照时间参数查询能预约的预约记录
        if (!params.containsKey("courseId")) {
            return listByTime(params);
        }
        //查询传入参数中课程id对应符合课程，
        // 如果不存在该课程，则也按照仅时间查询处理
        Integer courseId = ParamsUtil.getInteger(params, "courseId");
        CourseEntity course = courseService.getById(courseId);
        if (course == null) {
            return listByTime(params);
        }
        Integer weekStart = ParamsUtil.getInteger(params, "weekStart");
        Integer weekEnd = ParamsUtil.getInteger(params, "weekEnd");
        List<Integer> weeks = ParamsUtil.getBetweenIntegers(weekStart, weekEnd, 1);
        List<Integer> days = ParamsUtil.getIntegerList(params, "dayOfWeek");
        List<Integer> times = ParamsUtil.getIntegerList(params, "timeOfDay");
        //拿到容量大于课程学时数的所有实验室
        List<LabEntity> labs = labService.list(new QueryWrapper<LabEntity>().ge("capicity", course.getStuCount()));
        List<Integer> labIds = labs.stream().map(LabEntity::getId).collect(Collectors.toList());
        //在容量合适的实验室中，挑选在时间范围内、全都有空闲的实验室预约记录
        List<ReserInfoDTO> res = reservationService.listByTimeAndIds(weeks, days, times, labIds);
        if (res == null || res.size() == 0) {
            return R.ok().put("page", new PageUtils(List.of(), params));
        }
        return R.ok().put("page", new PageUtils(res, params));
    }

    /**
     * 分页查询出指定时间内的所有实验室预约记录
     * @param params
     * @return
     */
    @GetMapping("/listByTime")
    public R listByTime(@RequestParam Map<String, Object> params) {
        Integer weekStart = ParamsUtil.getInteger(params, "weekStart");
        Integer weekEnd = ParamsUtil.getInteger(params, "weekEnd");

        List<Integer> weeks = ParamsUtil.getBetweenIntegers(weekStart, weekEnd, 1);
        List<Integer> days = ParamsUtil.getIntegerList(params, "dayOfWeek");
        List<Integer> times = ParamsUtil.getIntegerList(params, "dayOfWeek");
        PageUtils page = reservationService.pageByTime(new Query<ReservationEntity>().getPage(params), weeks, days, times);
        return R.ok().put("page", page);
    }
    @GetMapping("/listByTid")
    public R listByTid(HttpServletRequest request,@RequestParam Map<String, Object> params) {
        Integer tid = (Integer) request.getAttribute("tid");
        log.debug("teacherID:{}",tid);
        if (tid == null)
            return R.error("不是老师，无权限预约");
        //根据tid找到老师的所有课程
        List<Integer> cids = courseService.getBaseMapper().selectList(
                new QueryWrapper<CourseEntity>().eq("teacher_id", tid))
                .stream()
                .map(CourseEntity::getId)
                .collect(Collectors.toList());
        log.debug("课程数:{}",cids.size());
        //根据课程id列表找到所有预约记录
        PageUtils page = reservationService.pageByCids(new Query<ReservationEntity>().getPage(params),cids);
        log.debug("查询到的预约记录:{}",page.getList().size());
        return R.ok().put("page",page);
    }
}
